home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Delphi Magazine Collection 2001
/
Delphi Magazine Collection 20001 (2001).iso
/
DISKS
/
Issue45
/
Clinic
/
DBHntGrd.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
2000-11-02
|
7KB
|
256 lines
unit DBHntGrd;
{$ifdef Ver80} { Delphi 1.0x }
{$define DelphiLessThan3}
{$endif}
{$ifdef Ver90} { Delphi 2.0x }
{$define DelphiLessThan3}
{$endif}
{$ifdef Ver93} { C++ Builder 1.0x }
{$define DelphiLessThan3}
{$endif}
interface
uses
WinProcs, WinTypes, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Grids, DBGrids;
type
THintDBGrid = class(TDBGrid)
private
FHintWnd: THintWindow;
protected
function CalcHintRect(MaxWidth: Integer;
const AHint: string; HintWnd: THintWindow): TRect;
procedure DoHint(X, Y: Integer);
public
procedure CMMouseEnter(var Msg: TMessage); message cm_MouseEnter;
procedure CMMouseLeave(var Msg: TMessage); message cm_MouseLeave;
procedure WMMouseMove(var Msg: TWMMouseMove); message wm_MouseMove;
end;
{$ifdef DelphiLessThan3}
{ The hint window in Delphi 1 and 2 would beep if you clicked it }
{ These modifications fix that }
TCustomHint = class(THintWindow)
private
procedure WMNCHitTest(var Msg: TWMNCHitTest);
message wm_NCHitTest;
protected
procedure CreateParams(var Params: TCreateParams); override;
end;
{ The private routine Forms.ForegroundTask was only made }
{ available in Delphi 3. This is a cheap'n'nasty version of it }
function ForegroundTask: Boolean;
{$endif}
procedure Register;
implementation
uses
DB, DBTables;
procedure Register;
begin
RegisterComponents('Clinic', [THintDBGrid]);
end;
{$ifdef DelphiLessThan3}
{ The private routine Forms.ForegroundTask was only made }
{ available in Delphi 3. This is a cheap'n'nasty version of it }
function ForegroundTask: Boolean;
begin
Result := FindControl(GetActiveWindow) <> nil
end;
{$endif}
{ THintStringGrid }
function THintDBGrid.CalcHintRect(MaxWidth: Integer;
const AHint: string; HintWnd: THintWindow): TRect;
{$ifdef DelphiLessThan3}
var
Buf: PChar;
begin
Result := Rect(0, 0, MaxWidth, 0);
{ Translate Pascal string to C, but take care of possible problematic }
{ values. Delphi 2 sometimes copies less than the full memo with StrPCopy }
Buf := StrAlloc(Length(AHint) + 1);
try
{$ifdef Win32}
Move(AHint[1], Buf^, Length(AHint));
{$else}
StrPCopy(Buf, AHint);
{$endif}
{ Ask Windows to do the hard calculation work }
DrawText(HintWnd.Canvas.Handle, Buf, -1, Result,
DT_CALCRECT or DT_LEFT or DT_WORDBREAK or DT_NOPREFIX);
finally
StrDispose(Buf);
end;
{ Add some breathing room }
Inc(Result.Right, 6);
Inc(Result.Bottom, 2);
{$else}
begin
{ Delphi 3+ makes this method available }
Result := HintWnd.CalcHintRect(Screen.Width, AHint, nil)
{$endif}
end;
procedure THintDBGrid.CMMouseEnter(var Msg: TMessage);
var
Pt: TPoint;
begin
GetCursorPos(Pt);
Pt := ScreenToClient(Pt);
DoHint(Pt.X, Pt.Y)
end;
procedure THintDBGrid.CMMouseLeave(var Msg: TMessage);
begin
inherited;
{ Could destroy it, but this takes less time }
if Assigned(FHintWnd) then
FHintWnd.ReleaseHandle;
end;
procedure THintDBGrid.DoHint(X, Y: Integer);
const
TextOffset = 2;
var
Col, Row, LogCol, LogRow: Longint;
R, OldR: TRect;
Pt: TPoint;
GPt: TGridCoord;
OldActive: Integer;
Text: String;
{$ifndef Win32}
CText: PChar;
{$endif}
begin
{ Check cell under mouse }
GPt := MouseCoord(X, Y);
Col := GPt.X;
Row := GPt.Y;
LogCol := Col;
LogRow := Row;
{ Title row needs to be taken account of }
if dgTitles in Options then Dec(LogRow);
{ Indicator column needs to be taken account of }
if dgIndicator in Options then Dec(LogCol);
Text := '';
if (LogCol >= 0) and (LogRow >= 0) then
begin
{ Get field text, taking memo fields into account }
OldActive := DataLink.ActiveRecord;
try
Datalink.ActiveRecord := LogRow;
{$ifdef Win32}
{ Delphi 2+ is easy for memos }
if not (Columns[LogCol].Field is TMemoField) then
Text := Columns[LogCol].Field.DisplayText
else
begin
Text := Columns[LogCol].Field.AsString;
end
{$else}
{ Delphi 1 is more tricky for memos - best I can manage }
{ is to copy contents to a string list and work from that }
if not (Fields[LogCol] is TMemoField) then
Text := Fields[LogCol].DisplayText
else
with TStringList.Create do
try
Assign(Fields[LogCol]);
CText := GetText;
try
{ Delphi 1 strings are at most 255 characters }
if StrLen(CText) > 255 then
Text := Copy(StrPas(CText), 1, 252) + '...'
else
Text := StrPas(CText)
finally
StrDispose(CText)
end
finally
Free
end;
{$endif}
finally
Datalink.ActiveRecord := OldActive
end
end;
{ If it is a cell, and in-place editor not present, }
{ and text is bigger than screen space, and not at design-time }
Canvas.Font := Font;
if (Text <> '') and not EditorMode and ForegroundTask and
(Canvas.TextWidth(Text) + TextOffset > ColWidths[Col]) and
not (csDesigning in ComponentState) then
begin
{ Make sure hint window exists }
if not Assigned(FHintWnd) then
begin
FHintWnd := HintWindowClass.Create(Self);
FHintWnd.Color := Application.HintColor;
end;
{ Set hint text }
Hint := Text;
{ Calculate rect size }
R := CalcHintRect(Screen.Width, Hint, FHintWnd);
{ Find target location }
Pt := ClientToScreen(CellRect(Col, Row).TopLeft);
{ Tweak position so it is the same as the grid cell (hopefully) }
{$ifdef DelphiLessThan3}
Inc(Pt.Y);
{$else}
Dec(Pt.X);
Dec(Pt.Y);
{$endif}
OffsetRect(R, Pt.X, Pt.Y);
if R.Right > Screen.Width then
OffsetRect(R, Screen.Width - R.Right, 0);
if R.Bottom > Screen.Height then
OffsetRect(R, Screen.Height - R.Bottom, 0);
{ Only draw it if it has moved - compare top-left }
{ (could compare whole rect but the hint sometimes grows itself) }
GetWindowRect(FHintWnd.Handle, OldR);
if not IsWindowVisible(FHintWnd.Handle) or
not ((R.Left = OldR.Left) and (R.Top = OldR.Top)) then
FHintWnd.ActivateHint(R, Hint)
end
else
if Assigned(FHintWnd) then
FHintWnd.ReleaseHandle
end;
procedure THintDBGrid.WMMouseMove(var Msg: TWMMouseMove);
begin
inherited;
DoHint(Msg.XPos, Msg.YPos)
end;
{$ifdef DelphiLessThan3}
{ TCustomHint }
procedure TCustomHint.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := Params.Style and not ws_Disabled;
end;
procedure TCustomHint.WMNCHitTest(var Msg: TWMNCHitTest);
begin
Msg.Result := HTTRANSPARENT;
end;
initialization
Application.ShowHint := not Application.ShowHint;
HintWindowClass := TCustomHint;
Application.ShowHint := not Application.ShowHint;
{$endif}
end.